﻿/*
 * GdoSqlCommand.prepareSpatialMetadata
 * 
 * initial implementation : 20.9.2008
 *
 * Copyright (c) Adam Sida, asida@centrum.cz.
 * All rights reserved.
 * 
 * for license see Petra.Gis.License.txt
 */
using System;
using System.Text.RegularExpressions;
using System.Data;
using System.Data.Common;
//using System.Data.SqlClient;
using Petra.Gis.DataServices;
using Petra.Gis.Geometry;
using Petra.Gis.Geometry.Support;
using Petra.Gis.DataServices.Metadata;


namespace Petra.Gis.DataServices.GDO.Sqlserver
{


  public partial class GdoSqlCommand : SpatialDbCommand
  {



    protected override FeatureMetadata getFeatureMetadata()
    {
      // if allready initialized, do nothing
      if (Metadata != null)
        return Metadata;

      if (this.CommandText == "" || this.CommandText == null)
        return null;

      if (this.Connection.State != ConnectionState.Open)
        return null;

      if (this.CommandType == CommandType.Text)
      {
        FeatureQualifier tq = parseTableQualifierFromSqlText(this.CommandText);
        if (tq == null)
          return null;
        else
        {
          //Metadata = getFeatureMetadata(tq.Catalog, tq.Schema, tq.Name);
          return getFeatureMetadata(tq.Catalog, tq.Schema, tq.Name);
        }
      }
      else
        return null;

      //// add metadata to extensions
      //if (this.Extensions.ContainsKey("FeatureMetadata"))
      //  this.Extensions["FeatureMetadata"] = _metadata;
      //else
      //  this.Extensions.Add("FeatureMetadata", _metadata);
    }




    protected override FeatureMetadata forceFeatureMetadata(string forceMetadataByFeatureName)
    {
      //if (Metadata != null)
      //  return _metadata;

      //FeatureQualifier f = parseFeatureQualifierFromLongName((string)this.Parameters["Petra.Gis.ForceMetadataFromSpecificFeature"].Value);
      FeatureQualifier f = parseFeatureQualifierFromLongName(forceMetadataByFeatureName);

      //Metadata = GetFeatureMetadata(f.Catalog, f.Schema, f.Name);
      return getFeatureMetadata(f.Catalog, f.Schema, f.Name);
    }




    protected override FeatureMetadata getFeatureMetadata(string catalog, string schema, string featureName)
    {
      // get feature/table metadata 
      DataTable mtdtT = this.Connection.GetSpatialSchema(SpatialSchemaTables.Features, new string[] { catalog, schema, featureName, null, null, null, null, null, null, null });

      if (mtdtT.Rows.Count != 1)
        throw new ArgumentException("invalid FeatureName specified, either not exists or ambiguitous");

      FeatureMetadata result = new FeatureMetadata()
      {
        Abstract = (string)mtdtT.Rows[0]["ABSTRACT"],
        Authority = (string)mtdtT.Rows[0]["AUTHORITY"],
        Name = (string)mtdtT.Rows[0]["FEATURE_NAME"],
        ContactInfo = ContactInfo.Parse((string)mtdtT.Rows[0]["CONTACTINFO"]),
        KeyWords = ((string)mtdtT.Rows[0]["KEYWORDS"]).Split(';'),
        Title = (string)mtdtT.Rows[0]["TITLE"],
        //Bounds = BoundingBox.Parse((string)mtdtT.Rows[0]["BOUNDS"])
      };

      // get geometry columns metadata
      DataTable mtdtTCS;
      mtdtT = this.Connection.GetSpatialSchema(SpatialSchemaTables.Fields, new string[] { catalog, schema, featureName, null, null, null, null });
      result.GeometryFieldsMetadata = new SpatialFieldMetadata[mtdtT.Rows.Count];
      for (int i = 0; i < mtdtT.Rows.Count; i++)
      {
        result.GeometryFieldsMetadata[i] = new SpatialFieldMetadata();
        result.GeometryFieldsMetadata[i].Name = (string)mtdtT.Rows[i]["FIELD_NAME"];
        // resolve coordinate systems...
        string csid = ((Guid)mtdtT.Rows[i]["COORDINATESYSTEM_ID"]).ToString();
        mtdtTCS = this.Connection.GetSpatialSchema(SpatialSchemaTables.CoordinateSystemsInfo, new string[] { csid, null });
        //gdosql have proprietary cs definition in db, must use parseCoordinateSystemInfo
        if (mtdtTCS.Rows[0]["COORDINATESYSTEM_INFO"] is System.DBNull)
          throw new ApplicationException("null COORDINATESYSTEM_INFO, cant create metadata");
        else
          result.GeometryFieldsMetadata[i].SRS = parseCoordinateSystemInfo((string)mtdtTCS.Rows[0]["COORDINATESYSTEM_INFO"]);

        //resolve domain geometry type
        switch ((int)mtdtT.Rows[0]["DOMAIN_GEOMETRY_TYPE"])
        {
          case 1:
            result.GeometryFieldsMetadata[i].DomainType = DomainGeometryTypeEnum.Line;
            break;
          case 2:
            result.GeometryFieldsMetadata[i].DomainType = DomainGeometryTypeEnum.Surface;
            break;
          case 3:
            result.GeometryFieldsMetadata[i].DomainType = DomainGeometryTypeEnum.Mixed;
            break;
          case 5:
          case 33:
            result.GeometryFieldsMetadata[i].DomainType = DomainGeometryTypeEnum.Label;
            break;
          case 10:
            result.GeometryFieldsMetadata[i].DomainType = DomainGeometryTypeEnum.Point;
            break;
          case 7:
            result.GeometryFieldsMetadata[i].DomainType = DomainGeometryTypeEnum.Mixed;
            break;
          case 4:
            result.GeometryFieldsMetadata[i].DomainType = DomainGeometryTypeEnum.Grid;
            break;
          default:
            throw new ApplicationException("invalid gdo domain geometry type " + (string)mtdtT.Rows[0]["DOMAIN_GEOMETRY_TYPE"]);
        }
      }
      return result;
    }




    protected FeatureQualifier parseTableQualifierFromSqlText(string cmdText)
    {

      if(cmdText == null)
        return null;

      // parse SQL using regex... try get FROM table_name
      // parses table name as following:
      // schema..table, schema.owner.table, owner.table, table
      string pattern = @"((?<from>(F|f)(R|r)(O|o)(M|m))\s*(" +
        @"(\[?(?<schemaname>\w+)\]?\.\[?(?<ownername>\w+)\]?\.\[?(?<tablename>\w+)\]?)|" +
        @"(\[?(?<schemaname>\w+)\]?\.\.\[?(?<tablename>\w+)\]?)|" +
        @"(\[?(?<ownername>\w+)\]?\.\[?(?<tablename>\w+)\]?)|" +
        @"(\[?(?<tablename>\w+)\]?))\s*" +
        @"(?<alias>\w+)?)+";

      Regex r = new Regex(pattern);
      Match m = r.Match(cmdText);

      FeatureQualifier result = new FeatureQualifier();

      if (m.Length < 1)
        //throw new ArgumentException("non readable command");
        return null;

      // must be only one occurrence of from
      // if multiple sql can be join or other complex query
      else if (m.Groups["from"].Captures.Count == 1)
      {
        result.Catalog = (m.Groups["schemaname"].Captures.Count == 1 ? m.Groups["schemaname"].Captures[0].Value : null);
        result.Schema = (m.Groups["ownername"].Captures.Count == 1 ? m.Groups["ownername"].Captures[0].Value : null);
        result.Name = m.Groups["tablename"].Captures[0].Value;


        if (m.Groups["alias"].Captures.Count > 0)
        {
          string sTmp = m.Groups["tablename"].Captures[0].Value.Trim().ToLower();
          if (!(sTmp == "where" || sTmp == "group" ||
               sTmp == "left" || sTmp == "right" ||
               sTmp == "inner" || sTmp == "outer" ||
               sTmp == "join"))
            result.Alias = sTmp;
        }

        return result;
      }
      return null;
    }


  }
}
